//
//  BKHttpRequestQueue.m
//  Pods
//
//  Created by baboy on 1/18/16.
//
//

#import "BKHttpRequestQueue.h"
#import "NSString+x.h"
#import "BKKitDefines.h"

@interface BKHttpRequestPoolItem: NSObject
@property(nonatomic, strong) id sesstionTask;
@property(nonatomic, strong) NSMutableArray *tasks;
@end
@implementation BKHttpRequestPoolItem
@end

@interface BKHttpRequestPool(){
    NSMutableDictionary *_pool;
}
@end
@implementation BKHttpRequestPool
+ (id)defaultPool {
    static id _pool = nil;
    static dispatch_once_t initOncePool;
    dispatch_once(&initOncePool, ^{
        _pool = [[BKHttpRequestPool alloc] init];
    });
    return _pool;
}
- (id)init{
    if (self = [super init]) {
        _pool = [NSMutableDictionary dictionary];
    }
    return self;
}
- (BOOL)addTask:(BKHttpRequestTask *_Nonnull)task{
    @synchronized (self) {
        BKHttpRequestPoolItem *item = [_pool valueForKey: task.identifier];
        if (!item) {
            item = [[BKHttpRequestPoolItem alloc] init];
            item.sesstionTask = task.sessionTask;
            item.tasks = [NSMutableArray array];
            [_pool setObject:item forKey: task.identifier];
        }
        [item.tasks addObject: task];
        return YES;
    }
}
- (BOOL)taskExists:(NSString *_Nonnull)identifier{
    @synchronized (self) {
        BKHttpRequestPoolItem *item = [_pool valueForKey:identifier];
        if (!item) {
            return NO;
        }
        return YES;
    }
}
- (BOOL)removeTask:(BKHttpRequestTask *_Nonnull)task{
    @synchronized (self) {
        BKHttpRequestPoolItem *item = [_pool valueForKey:task.identifier];
        if (item) {
            if ([item.tasks containsObject:task]) {
                [item.tasks removeObject:task];
            }
            if (item.tasks.count == 0) {
                [_pool removeObjectForKey:task.identifier];
            }
        }
        return YES;
    }
}
- (id _Nullable)sessionTaskForIdentifier:(NSString *_Nonnull)identifier{
    @synchronized (self) {
        BKHttpRequestPoolItem *item = [_pool valueForKey:identifier];
        if (item) {
            return item.sesstionTask;
        }
        return nil;
    }
}
- (BOOL)clearTasksWithIdentifier:(NSString *_Nonnull)identifier{
    @synchronized (self) {
        [_pool removeObjectForKey:identifier];
        return YES;
    }
}
- (BOOL)clearTasksWithIdentifier:(NSString *_Nonnull)identifier runWithBlock:(nullable void(^)(BKHttpRequestTask *_Nonnull)) block{
    @synchronized (self) {
        BKHttpRequestPoolItem *item = [_pool valueForKey:identifier];
        if (item) {
            for (NSInteger i = 0; i < item.tasks.count; i++) {
                BKHttpRequestTask *task = [item.tasks objectAtIndex:i];
                block(task);
            }
            [self clearTasksWithIdentifier:identifier];
        }
        return YES;
    }
}



@end
@implementation BKHttpRequestTask
- (id _Nonnull)initWithTask:(NSURLSessionTask *_Nullable)task UUID:(NSUUID *_Nullable)uuid  identifier:(NSString *_Nullable)identifier{
    if (self = [super init]) {
        self.sessionTask = task;
        self.uuid = uuid;
        self.identifier = identifier;
    }
    return self;
}
- (id _Nonnull)initWithIdentifier:(NSString *_Nullable)identifier{
    if (self = [super init]) {
        self.identifier = identifier;
    }
    return self;
}
- (void)cancel{
    if (self.delegate) {
        [self.delegate cancelTask:self];
    }else{
        [self.sessionTask cancel];
    }
}
@end
@interface BKHttpRequestQueue()
@end
@implementation BKHttpRequestQueue
- (id)init{
    if (self = [super init]) {
        self.queue = [NSMutableArray array];
        self.maxConcurrentTaskCount = 10;
    }
    return self;
}
//当前正在执行的程序数量
- (int)currentRunningTaskCount{
    @synchronized(self) {
        int n = 0;
        for (int i=0; i<self.queue.count; i++) {
            BKHttpRequestRelativeTask *task = [self.queue objectAtIndex:i];
            if (task.task.state == NSURLSessionTaskStateRunning) {
                ++n;
            }
        }
        DLOG(@"%d",n);
        return n;
    }
}
- (BOOL)cancelTask:(BKHttpRequestTask *)task{
    @synchronized(self) {
        BKHttpRequestRelativeTask *relativeTask = [self taskForIdentifier:task.identifier];
        for (NSInteger i = 0; i < relativeTask.handlers.count; i++) {
            BHttpResponseHandler *handler = [relativeTask.handlers objectAtIndex:i];
            if ([handler.uuid isEqual:task.uuid]) {
                [relativeTask.handlers removeObject:handler];
                if (relativeTask.handlers.count == 0) {
                    [self removeTask:relativeTask];
                    break;
                }
            }
        }
        
    }
    [self startNext];
    return YES;
}
- (void)removeTask:(BKHttpRequestRelativeTask *)relativeTask{
    @synchronized(self) {
        [relativeTask.handlers removeAllObjects];
        [self.queue removeObject:relativeTask];
    }
    [self startNext];
}
- (void)clearQueue{
    @synchronized(self) {
        for (NSInteger i=self.queue.count-1; i>=0; i++) {
            BKHttpRequestRelativeTask *relativeTask = [self.queue objectAtIndex:i];
            if (relativeTask.task.state == NSURLSessionTaskStateCompleted || relativeTask.task.state == NSURLSessionTaskStateCanceling) {
                [self.queue removeObject:relativeTask];
                break;
            }
        }
    }
    [self startNext];
}
- (void)startNext{
    @synchronized(self) {
        if([self currentRunningTaskCount] < self.maxConcurrentTaskCount){
            for (int i=0; i<self.queue.count; i++) {
                BKHttpRequestRelativeTask *relativeTask = [self.queue objectAtIndex:i];
                if (relativeTask.task.state == NSURLSessionTaskStateSuspended) {
                    [relativeTask.task resume];
                    break;
                }
            }
            
        }
    }
}

- (BKHttpRequestRelativeTask *_Nullable)taskForIdentifier:(NSString *_Nonnull)identifier{
    for (int i=0; i<self.queue.count; i++) {
        BKHttpRequestRelativeTask *relativeTask = [self.queue objectAtIndex:i];
        if ([relativeTask.identifier isEqualToString:identifier]) {
            return relativeTask;
        }
    }
    return nil;
}
- (void)addHandler:(BHttpResponseHandler *_Nullable)handler identifier:(NSString *_Nonnull)identifier{
    @synchronized(self) {
        BKHttpRequestRelativeTask *relativeTask = [self taskForIdentifier:identifier];
        [relativeTask addHandler:handler];
    }
}
- (void)addTask:(BKHttpRequestRelativeTask *)relativeTask{
    @synchronized(self) {
        [self.queue addObject:relativeTask];
    }
    [self startNext];
}
@end

@implementation  BHttpResponseHandler : NSObject
- (id)initWithUUID:(NSUUID *)uuid
           success:(nullable void (^)(id task, id data))success
           failure:(nullable void (^)(id task, id data, NSError* error))failure{
    if (self = [super init]) {
        self.uuid = uuid;
        self.successBlock = success;
        self.failureBlock = failure;
    }
    return self;
}
@end

@implementation  BKHttpRequestRelativeTask
- (id)initWithIdentifier:(NSString *)identifier task:(NSURLSessionTask *)task{
    if (self = [super init]) {
        self.identifier = identifier;
        self.task = task;
        self.handlers = [NSMutableArray array];
    }
    return self;
}
- (void)addHandler:(BHttpResponseHandler*)handler{
    [self.handlers addObject:handler];
}
- (void)removeHandler:(BHttpResponseHandler*)handler{
    [self.handlers removeObject:handler];
}
@end

